﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PBMessage;
namespace GameUnit
{
    public class Unit : MonoBehaviour
    {
        public Hashtable UnitTable;
        public GamePlayer GamePlayer;
        public long UnitId;
        public int MaxHP;
        public int faceDir = 1;
        public bool IsDie = false;
        protected int hp;
        public int HP
        {
            get { return hp; }
            set
            {
                if (!this.IsDie)
                {
                    hp = value;
                    CallEvent("hp-change", "");
                    if (hp <= 0)
                    {
                        this.IsDie = true;
                    }
                }
            }
        }

        public int MaxMP;
        protected int mp;
        public int MP { set; get; }

        protected int shiled;
        public int Shiled
        {
            get { return shiled; }
            set
            {
                if (value != shiled)
                {
                    shiled = value;
                    CallEvent("shiled-change", "");
                }

            }
        }
        public float MoveSpeed;
        public Dictionary<string, Actor> Actors = new Dictionary<string, Actor>();
        public Dictionary<string, Ability> Abilities = new Dictionary<string, Ability>();
        public List<Weapon> Weapons = new List<Weapon>();
        public List<UWidget> UWidgets = new List<UWidget>();
        public List<Behavior> Behaviors = new List<Behavior>();

        public delegate void UnitEventFn(string eventName, string subMsg);
        public Dictionary<string, List<UnitEventFn>> UnitEvents = new Dictionary<string, List<UnitEventFn>>();

        public GameScene CurScene;
        Hashtable TriggerEventDic = new Hashtable();
        public void Init(Hashtable unitTable)
        {
            this.CurScene = Game.Scene.Cur<GameScene>();
            this.UnitTable = unitTable;
            this.MaxHP = (int)unitTable[":hp"];
            this.MaxMP = (int)unitTable[":mp"];
            this.hp = MaxHP;
            this.mp = MaxMP;
            this.MoveSpeed = (float)unitTable[":move-speed"];
            this.transform.localScale = Vector3.one * (float)unitTable[":scale"];
            //init actors
            object[] actorlst = (object[])unitTable[":actors"];
            for (int i = 0; i < actorlst.Length; i++)
            {
                Hashtable actorIndexDic = (Hashtable)actorlst[i];
                string actorName = (string)actorIndexDic[":name"];
                Hashtable actorDic = (Hashtable)ActorManager.ActorsTable[actorName];
                Actor newActor = new Actor(actorDic);
                this.Actors.Add(actorName, newActor);
                newActor.OnLoad(this);
            }
            //init ability
            object[] abilitylst = (object[])unitTable[":abilities"];
            for (int i = 0; i < abilitylst.Length; i++)
            {
                Hashtable abilityTable = (Hashtable)abilitylst[i];
                string abilityKey = (string)abilityTable[":name"];
                Hashtable AbilityData = (Hashtable)UnitManager.AbilitiesTable[abilityKey];
                string abilityType = (string)AbilityData[":type"];
                Ability newAbility = (Ability)gameObject.AddComponent(abilityType);
                newAbility.Unit = this;
                newAbility.Init(AbilityData);
                Abilities.Add(abilityKey, newAbility);
            }
            //init weapons
            object[] weaponlst = (object[])unitTable[":weapons"];
            for (int i = 0; i < weaponlst.Length; i++)
            {
                Hashtable weaponIndexMap = (Hashtable)weaponlst[i];
                Hashtable weaponConfig = WeaponManager.GetWeapon((string)weaponIndexMap[":name"]);
                Weapon newWeapon = WeaponManager.CreateWeapon(weaponConfig, this);
                newWeapon.transform.parent = transform;
                this.Weapons.Add(newWeapon);
            }
            //init unit widget
            object[] uWidgetlst = (object[])unitTable[":unit-widget"];
            for (int i = 0; i < uWidgetlst.Length; i++)
            {
                Hashtable uWidgetItemDic = (Hashtable)uWidgetlst[i];
                string uWidgetName = (string)uWidgetItemDic[":type"];
                GameObject newUWidgetG = new GameObject(uWidgetName);
                UWidget newUWidget = (UWidget)newUWidgetG.AddComponent(uWidgetName);
                newUWidget.Init(this);
                newUWidgetG.transform.parent = transform;
                UWidgets.Add(newUWidget);

            }
            //init behavior
            object[] behaviorlst = (object[])unitTable[":behaviors"];
            for (int i = 0; i < behaviorlst.Length; i++)
            {
                Hashtable behaviorDic = (Hashtable)behaviorlst[i];
                string behaviorName = (string)behaviorDic[":name"];
                Behavior newBehavior = BehaviorManager.CreateBehavior(behaviorName, this,i);
                this.Behaviors.Add(newBehavior);
            }
        }


        public void OnLoad()
        {
            foreach (KeyValuePair<string, Ability> ability in Abilities)
            {
                ability.Value.OnLoad();
            }
            this.Behaviors.ForEach((b) => { b.OnLoad(); });
            this.UWidgets.ForEach((w) => { w.OnLoad(); });
            CallEvent("UnitCreate", "create");
        }

        public void CallEvent(string eventName, string subMsg)
        {
            if (this.UnitEvents.ContainsKey(eventName))
            {
                foreach (UnitEventFn ue in UnitEvents[eventName])
                {
                    ue(eventName, subMsg);
                }
            }
            TriggerEventDic["event-name"] = new SGLisp.StringNode(eventName);
            TriggerEventDic["trigger-unit"] = new SGLisp.ObjectNode(this);
            this.CurScene.SceneTrigger.Trigger.CallEvent("Unit", TriggerEventDic);
        }

        public void AddEventHandler(string eventName, UnitEventFn unitEventFn)
        {
            if (!UnitEvents.ContainsKey(eventName))
            {
                UnitEvents[eventName] = new List<UnitEventFn>();
            }
            UnitEvents[eventName].Add(unitEventFn);
        }

        public virtual void ServerUpdate(SC_ServerUpdate updatePacket)
        {
            foreach (KeyValuePair<string, Ability> ability in this.Abilities)
            {
                ability.Value.ServerUpdate(updatePacket);
            }
        }


        public virtual void Handler_ServerSyncAttr(PBMessage.SC_SyncUnit unitData)
        {
            this.HP = unitData.HP;
            this.MP = unitData.MP;
            this.Shiled = unitData.Shiled;
            this.IsDie = unitData.IsDie;
        }

        public Behavior GetBehavior(string behaviorName)
        {
            for (int i = 0; i < this.Behaviors.Count; i++)
            {
                if (this.Behaviors[i].BehaviorName == behaviorName)
                {
                    return this.Behaviors[i];
                }
            }
            return null;
        }

        public Behavior GetBehaviorByUUID(long uuid) 
        {
            return this.Behaviors.Find((behavior) => {return behavior.UUID==uuid; });
        }
    }
}